home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr50 / vbprint.zip / VBPRINT.C < prev    next >
C/C++ Source or Header  |  1993-05-07  |  48KB  |  1,409 lines

  1. /*************************************************************************
  2.     Print Engine for Visual Basic
  3.     Printing utilities for hardcopy output
  4.  
  5.     Written by Barry Nolte
  6.  
  7.     06-28-92    File Created
  8.     11-12-92    Added Graphics Functions
  9.     01-17-93    General Cleanup of Sources
  10.     02-03-93    Simple Bug Fixes
  11.  
  12. *************************************************************************/
  13.  
  14. // COPYRIGHT:
  15. //
  16. //   (C) Copyright Microsoft Corp. 1993.  All rights reserved.
  17. //
  18. //   You have a royalty-free right to use, modify, reproduce and
  19. //   distribute the Sample Files (and/or any modified version) in
  20. //   any way you find useful, provided that you agree that
  21. //   Microsoft has no warranty obligations or liability for any
  22. //   Sample Application Files which are modified.
  23. //
  24.  
  25. #include <windows.h>
  26. #include <drivinit.h>
  27. #include <commdlg.h>
  28. #include <memory.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include "vbprint.h"
  32.  
  33. // DLL Version Numbers
  34. #define MAJOR_VERSION     1
  35. #define MINOR_VERSION     0
  36.  
  37. #define BORDER_WIDTH    2        // Default border in points
  38.  
  39. /*************************************************************************
  40.  
  41.     GLOBAL VARIABLES
  42.  
  43. *************************************************************************/
  44.  
  45. static    HANDLE        hInst;        // Handle to calling app
  46. static    HWND        hWndApp;    // Handle ot calling apps main window
  47. static    PRINTDLG    ppPrinter;    // Structure of printer properties
  48.  
  49. // Misc Procs
  50. static    FARPROC        lpfnPrintDlgProc;    // Printing dialog proc
  51. static    FARPROC        lpfnAbortProc;        // Printing about proc
  52. static  BOOL        fAbort;
  53.  
  54. static    struct tagPrinterInfo    // Information on printer needed to place objects correctly
  55.     {
  56.         POINT    ptPageSize;            // Size of the page
  57.         RECT    rcUnprintable;        // Unprintable regions of the printer
  58.         RECT    rcMargins;            // Margins that are set in the Page Layout Function
  59.         POINT    ptResolution;        // Printer Resolution in device DPI
  60.  
  61.     } PrinterInfo;
  62.  
  63. static    struct tagPageInfo        // Information on where I'm printing on the page
  64.     {
  65.         POINT    ptCurrentPos;        // Current Print Position
  66.         DWORD    dwCurLineWidth;        // Current Line Width, good for multiple calls to ParagraphText
  67.         int        nTabStop;            // Current Tab Stop value
  68.         BOOL    bPageDirty;            // Is the page dirty?
  69.  
  70.     } PageInfo;
  71.  
  72. static struct tagParagraphInfo    // Information on paragraph attributes
  73.     {
  74.         HFONT        hFont;            // Handle to paragraphs default font
  75.         HFONT        hOldFont;        // Handle to previous font
  76.         TEXTMETRIC    tm;                // Text metric struct that has info on the font
  77.         DWORD        dwWidth;        // Width of column to print into
  78.         int            nStyle;            // Border and Font Attributes
  79.         WORD        wBorderWidth;    // Border Width in device units (HIBYTE = Horizontal, LOBYTE = Vertical)
  80.         int            nWidth[LAST_CHAR - FIRST_CHAR + 1];    // Widths of all the fonts characters
  81.         int            nSpaceBefore;        // Space before Paragraph in Points
  82.         int         nSpaceAfter;        // Space After Paragraph in Points
  83.         int            nLeftIndent;        // Paragraph Left Indent size, good for check box justification
  84.  
  85.     } ParagraphInfo;
  86.  
  87. static struct tagColumnInfo        // Information on printing columns
  88.     {
  89.         HFONT        hFont;                            // Handle to paragraphs default font
  90.         HFONT        hOldFont;                        // Handle to previous font
  91.         TEXTMETRIC    tm;                                // Text Metric struct that has info on the font
  92.         WORD        wBorderWidth;                    // Border Width in device units (HIBYTE = Horizontal, LOBYTE = Vertical)
  93.         int         nNumColumns;                    // Number of vertical Columns
  94.         int         nCellHeight;                    // Height of Cells
  95.         int         rgColumnWidths[MAX_COLUMNS];        // Widths of Columns
  96.         int            nWidth[LAST_CHAR - FIRST_CHAR + 1];    // Widths of all the fonts characters
  97.         int             nStyle;                            // Border and Font attributes
  98.  
  99.     } ColumnInfo;
  100.  
  101. /*************************************************************************
  102.     PROTOTYPES
  103. *************************************************************************/
  104.  
  105. int     FAR PASCAL     PrinterSetup(HWND hWnd);
  106. int     FAR PASCAL     InitializePrinter(HWND hWnd);
  107. int     FAR PASCAL    PageLayoutSetup(int nTop, int nRight, int nBottom, int nLeft);
  108. BOOL                DoCommDlgError(HWND hWnd, DWORD dError);
  109. int     FAR PASCAL     DonePrinting(void);
  110. int     FAR PASCAL     StartParagraph(LPSTR szFontName, int nFontSize, int nStyle);
  111. int     FAR PASCAL    FinishParagraph(void);
  112. int     FAR PASCAL     PrintHeadline(LPSTR szHeadLine, LPSTR szFontName, int nFontSize, int nStyle);
  113. int     FAR PASCAL    ParagraphText(LPSTR szText);
  114. int     FAR PASCAL    EjectPage (void);
  115. int                 TextOutAtCurPos(LPSTR szText);
  116. int                 GetColumnOffset(int nColumn);
  117. int                 CellDrawText(HDC hDC, LPSTR szText, LPRECT rc);
  118. BOOL                GetUnprintableRegion(HDC hDCPrn);
  119. BOOL                GetPrinterResolution(HDC hDCPrn);
  120. BOOL    FAR PASCAL    PrnAbortProc(HDC hDCPrn, short nCode);
  121. BOOL    FAR PASCAL    PrintDlgProc(HWND hDlg, WORD message, WORD wParam, LONG lParam);
  122. int     FAR PASCAL    PrintDLLVersion(VOID);
  123. BOOL    FAR PASCAL    SetParagraphSpacing(int nSpaceBefore, int nSpaceAfter);
  124. BOOL    FAR PASCAL    SetBorderWidth(int nWidth);
  125. int     FAR PASCAL    SetUpColumns(int nNumColumns, LPINT nC, LPSTR szFontName, int nFontSize, int nStyle);
  126. int     FAR PASCAL    PrintColumnText(LPSTR szText);
  127. int     FAR PASCAL    EndColumnPrinting(VOID);
  128. int     FAR PASCAL    PrintColumnHeaders(LPSTR szHeader, int nNumColumns, LPINT nC, LPSTR szFontName, int nFontSize, int nStyle);
  129. HDC                 GetPrinterDC(void);
  130. BOOL    FAR PASCAL    KillJob(void);
  131. BOOL    FAR PASCAL    PrinterName(LPSTR szPrinterName);
  132. BOOL    FAR PASCAL    PrinterPort(LPSTR szPortName);
  133. BOOL    FAR PASCAL    IsPageDirty(void);
  134. int     FAR PASCAL    PagePosY(void);
  135. int     FAR PASCAL    PagePosX(void);
  136. int     FAR PASCAL    PageSizeY(void);
  137. int     FAR PASCAL    PageSizeX(void);
  138. BOOL    FAR PASCAL    MoveYPos(int nY);
  139. int     FDrawLine(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY);
  140. int     FDrawRectangle(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY);
  141. int     FDrawRndRectangle(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY, int nElpX, int nElpY);
  142. int     FDrawEllipse(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY);
  143. BOOL    FAR PASCAL    DrawLine(int nX1, int nY1, int nX2, int nY2);
  144. BOOL    FAR PASCAL    DrawRectangle(int nX1, int nY1, int nX2, int nY2);
  145. BOOL    FAR    PASCAL    DrawRndRectangle(int nX1, int nY1, int nX2, int nY2, int nX3, int nY3);
  146. BOOL    FAR PASCAL    DrawEllipse(int nX1, int nY1, int nX2, int nY2);
  147.  
  148. /*************************************************************************
  149.     DLL initialization, called once when loaded
  150. *************************************************************************/
  151.  
  152. int FAR PASCAL LibMain(HANDLE hInstance, WORD wDataSeg, WORD wHeapSize, LPSTR lpszCmdLine)
  153. {
  154.     hInst = hInstance;        // Save this for later, we may need it
  155.  
  156.     /* Set all structure members to zero. */
  157.  
  158.     _fmemset(&ppPrinter, 0, sizeof(PRINTDLG));
  159.  
  160.     return TRUE;
  161.  
  162. }
  163.  
  164.  
  165. /*************************************************************************
  166.     Initialize Printer Driver and set defaults
  167. *************************************************************************/
  168.  
  169. int FAR PASCAL InitializePrinter(HWND hWnd)
  170. {
  171.  
  172.     char szQueueName[80]={""};
  173.  
  174.     hWndApp = hWnd;            // Save the calling apps window handle so we can put up dialogs
  175.  
  176.     fAbort = FALSE;
  177.  
  178.     PageInfo.bPageDirty = FALSE;
  179.  
  180.     ppPrinter.hDC = GetPrinterDC();
  181.  
  182.     if (ppPrinter.hDC)
  183.     {
  184.         // Do stuff for AbortProc and Printing Dialog
  185.  
  186.         lpfnAbortProc = MakeProcInstance(PrnAbortProc, hInst);
  187.         Escape(ppPrinter.hDC, SETABORTPROC, NULL, (LPSTR)(long)lpfnAbortProc, (LPSTR)NULL);
  188.  
  189.            GetUnprintableRegion(ppPrinter.hDC);
  190.            GetPrinterResolution(ppPrinter.hDC);
  191.            LoadString(hInst, IDS_QUEUE_NAME, (LPSTR)szQueueName, 80);
  192.         Escape(ppPrinter.hDC, STARTDOC,lstrlen((LPSTR)szQueueName) ,(LPSTR)szQueueName, NULL);
  193.  
  194.         // Temp Defaults
  195.  
  196.         // Setup defaults
  197.  
  198.         // Set Margins to 1" all around
  199.         PrinterInfo.rcMargins.top =
  200.         PrinterInfo.rcMargins.bottom =
  201.         PrinterInfo.rcMargins.left =
  202.         PrinterInfo.rcMargins.right = (int)(INCH * (PrinterInfo.ptResolution.x * 0.01));
  203.  
  204.         // Start at upper left hand corner
  205.         PageInfo.ptCurrentPos.x = PrinterInfo.rcMargins.left;
  206.         PageInfo.ptCurrentPos.y = PrinterInfo.rcMargins.top;
  207.  
  208.         // Default Tab Stops = 1/2"
  209.         PageInfo.nTabStop = (int)(HALF_INCH * (PrinterInfo.ptResolution.x * 0.01));
  210.  
  211.         // Default Paragraph Spacing
  212.         ParagraphInfo.nSpaceBefore        = (int)(QUARTER_INCH * (PrinterInfo.ptResolution.y * 0.01));
  213.         // No Indent By Default
  214.         ParagraphInfo.nLeftIndent    = 0;
  215.  
  216.         return TRUE;
  217.     }
  218.     else
  219.     {
  220.         DoCommDlgError(hWnd, CommDlgExtendedError());
  221.         return FALSE;
  222.     }
  223.  
  224. }
  225.  
  226. /*************************************************************************
  227.     Setup for the start of a paragraph, set text attributes
  228. *************************************************************************/
  229.  
  230. int    FAR PASCAL     StartParagraph(LPSTR szFontName, int nFontSize, int nStyle)
  231. {
  232.     int nFontWeight;        // Weight of the font
  233.     BYTE bFontItalic;        // Italic flag
  234.  
  235.     // Check for bogus font size values
  236.     nFontSize = min(nFontSize, MAX_FONT_SIZE);        // No bigger than
  237.     nFontSize = max(nFontSize, MIN_FONT_SIZE);        // No smaller than
  238.  
  239.     // Get weight of font
  240.     if(nStyle & BOLD_FONT)     nFontWeight = FW_BOLD;
  241.     else                     nFontWeight = FW_NORMAL;
  242.  
  243.     // Get font slant
  244.     if(nStyle & ITALIC_FONT)    bFontItalic = 1;
  245.     else                        bFontItalic = 0;
  246.  
  247.     // Remember Border Style and Size
  248.     ParagraphInfo.nStyle = nStyle;
  249.     ParagraphInfo.wBorderWidth =  (WORD)(((PrinterInfo.ptResolution.x * BORDER_WIDTH) / 72) << 8);
  250.     ParagraphInfo.wBorderWidth += (WORD)((PrinterInfo.ptResolution.y * BORDER_WIDTH) / 72);
  251.  
  252.     // Setup Text Attributes
  253.     SetBkMode(ppPrinter.hDC, TRANSPARENT);            // Show whatever was there before through the text
  254.     SetTextColor(ppPrinter.hDC, 0);                    // Black Text
  255.     SetBkColor(ppPrinter.hDC, 0x00FFFFFF);            // White Background
  256.     SetTextAlign(ppPrinter.hDC, TA_TOP|TA_LEFT);    // Text aligned at top, left of bounding box
  257.  
  258.     ParagraphInfo.hFont = CreateFont((int)((PrinterInfo.ptResolution.y * nFontSize) / 72),
  259.                                        0, 0, 0,
  260.                                        nFontWeight,
  261.                                        bFontItalic,
  262.                                        0, 0,
  263.                                        ANSI_CHARSET,
  264.                                        OUT_DEFAULT_PRECIS,
  265.                                        CLIP_DEFAULT_PRECIS,
  266.                                        DEFAULT_QUALITY,
  267.                                        VARIABLE_PITCH | FF_DONTCARE,
  268.                                        szFontName);
  269.     if(ParagraphInfo.hFont)    // If we get the font, selected and get the metrics and width
  270.     {
  271.         ParagraphInfo.hOldFont = SelectObject(ppPrinter.hDC, ParagraphInfo.hFont);
  272.         GetTextMetrics(ppPrinter.hDC, (LPTEXTMETRIC)&ParagraphInfo.tm);
  273.         GetCharWidth(ppPrinter.hDC, FIRST_CHAR, LAST_CHAR, (LPINT)&ParagraphInfo.nWidth);
  274.     }
  275.  
  276.  
  277.     // Set Current Line Width to Zero
  278.     PageInfo.dwCurLineWidth = 0;
  279.  
  280.     // See if first line will fit on page
  281.     if((PageInfo.ptCurrentPos.y += ParagraphInfo.nSpaceBefore) > (PrinterInfo.ptPageSize.y - PrinterInfo.rcMargins.bottom - ParagraphInfo.tm.tmHeight - ParagraphInfo.tm.tmExternalLeading))
  282.     {
  283.         EjectPage();        // Sets current positon too
  284.     }
  285.  
  286.     // Get Indent/Check Box Info
  287.     if(nStyle & CHECK_BOX)
  288.     {
  289.         WORD wBorderWidth;
  290.  
  291.         wBorderWidth = ParagraphInfo.wBorderWidth;        // Save the current Border width
  292.         SetBorderWidth(0);
  293.  
  294.         // Set Indent Value
  295.         ParagraphInfo.nLeftIndent    = (int)(QUARTER_INCH * (PrinterInfo.ptResolution.x * 0.01));    // Default Paragraph Indent
  296.         // Draw Check Box
  297.         FDrawRectangle(    ppPrinter.hDC,
  298.                         PrinterInfo.rcMargins.left,
  299.                         PageInfo.ptCurrentPos.y + ParagraphInfo.tm.tmExternalLeading,
  300.                         PrinterInfo.rcMargins.left  + (int)(EIGHTH_INCH * (PrinterInfo.ptResolution.x * 0.01)),
  301.                         PageInfo.ptCurrentPos.y + (int)(EIGHTH_INCH * (PrinterInfo.ptResolution.y * 0.01)) + ParagraphInfo.tm.tmExternalLeading);
  302.  
  303.         ParagraphInfo.wBorderWidth = wBorderWidth;        // Restore Border width
  304.  
  305.     }
  306.     else
  307.     {
  308.         ParagraphInfo.nLeftIndent    = 0;
  309.     }
  310.  
  311.     if(ParagraphInfo.nStyle & TOP_BORDER)            // Top Border Line
  312.         FDrawLine(    ppPrinter.hDC,
  313.                     PrinterInfo.rcMargins.left - (int)(HIBYTE(ParagraphInfo.wBorderWidth)),
  314.                     PageInfo.ptCurrentPos.y - (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2),
  315.                     PrinterInfo.ptPageSize.x - PrinterInfo.rcMargins.right + (int)(HIBYTE(ParagraphInfo.wBorderWidth)),
  316.                     PageInfo.ptCurrentPos.y - (int)(LOBYTE(ParagraphInfo.wBorderWidth)/2));
  317.  
  318.     // Width of column to print into
  319.     ParagraphInfo.dwWidth =     PrinterInfo.ptPageSize.x -
  320.                                 PrinterInfo.rcMargins.left -
  321.                                 PrinterInfo.rcMargins.right -
  322.                                 ParagraphInfo.nLeftIndent;
  323.  
  324.     // Start at left margin
  325.     PageInfo.ptCurrentPos.x = PrinterInfo.rcMargins.left + ParagraphInfo.nLeftIndent;
  326.  
  327.  
  328.     if(ParagraphInfo.hFont)    // If the font was generated, then we're cool
  329.         return TRUE;
  330.     else                    // Otherwise we're not
  331.         return FALSE;
  332. }
  333.  
  334.  
  335. /*************************************************************************
  336.     Print the actual paragraph taking in to consideration tab's
  337.     returns, etc...
  338. *************************************************************************/
  339.  
  340. int    FAR PASCAL    ParagraphText(LPSTR szText)
  341. {
  342.     char far *cpStart;                      // Pointer in string to print
  343.     char far *cpCurrent;
  344.     char far *cpEnd;
  345.     HGLOBAL    hText;
  346.     LPSTR    lpText;
  347.  
  348.     PageInfo.bPageDirty = TRUE;
  349.  
  350.     // Get our own private copy of the text
  351.     hText = GlobalAlloc(GHND, lstrlen((LPSTR)szText)+1);
  352.  
  353.     if(!hText) return FALSE;
  354.  
  355.     lpText = GlobalLock(hText);
  356.  
  357.     if(!lpText) return FALSE;
  358.  
  359.     lstrcpy((LPSTR)lpText, (LPSTR) szText);
  360.  
  361.     cpStart = cpCurrent = cpEnd = (LPSTR)lpText;    // All pointers to the start of the text string
  362.  
  363.     if(cpStart == NULL) return TRUE;        // If the string is NULL, thats alright, just don't do anything
  364.  
  365.  
  366.     while(*cpCurrent != NULL)
  367.     {
  368.         switch(*cpCurrent)
  369.         {
  370. /* TAB */    case '\t'    :    cpEnd = cpCurrent;
  371.                             *cpEnd = 0;                            // Set end of string to null
  372.                             TextOutAtCurPos((LPSTR)cpStart);    // Print text up to tab
  373.                             PageInfo.ptCurrentPos.x += LOWORD(GetTextExtent(ppPrinter.hDC, (LPSTR)cpStart, lstrlen((LPSTR)cpStart)));
  374.                             PageInfo.ptCurrentPos.x = (PageInfo.nTabStop * ((PageInfo.ptCurrentPos.x / PageInfo.nTabStop)+1));
  375.                             PageInfo.dwCurLineWidth = PageInfo.ptCurrentPos.x - PrinterInfo.rcMargins.left;
  376.                             cpStart = cpCurrent = cpEnd+1;
  377.                             break;
  378.  
  379. /* CR */    case '\r'    :    cpEnd = cpCurrent;
  380.                             *cpEnd = 0;                            // Set end of string to null
  381.                             TextOutAtCurPos((LPSTR)cpStart);    // Print the text
  382.                             // Next Line Down
  383.                             PageInfo.ptCurrentPos.y += ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading;
  384.                             if(PageInfo.ptCurrentPos.y > PrinterInfo.ptPageSize.y - PrinterInfo.rcMargins.bottom - ParagraphInfo.tm.tmHeight - ParagraphInfo.tm.tmExternalLeading)
  385.                             {
  386.                                 EjectPage();
  387.                             }
  388.                             // Start at left margin
  389.                             PageInfo.ptCurrentPos.x = PrinterInfo.rcMargins.left + ParagraphInfo.nLeftIndent;
  390.                             cpStart = cpCurrent = cpEnd+1;        // Set everything to start of next line
  391.                             if(*cpStart == '\n')                // Get rid of those dang line feeds
  392.                                 cpStart = cpEnd = ++cpCurrent;
  393.  
  394.                             // Clear Width
  395.                             PageInfo.dwCurLineWidth = 0;
  396.                             break;
  397.  
  398. /* NULL */    case NULL    :    cpEnd = cpCurrent; goto showline;
  399.                             break;
  400.  
  401.             default        :    if(*cpCurrent < FIRST_CHAR) *cpCurrent = ' ';    // Set any control chars to space
  402.                             PageInfo.dwCurLineWidth += ParagraphInfo.nWidth[(int)(*cpCurrent) - FIRST_CHAR];        // Width of character
  403.                             if(*cpCurrent == ' ') cpEnd = cpCurrent;        // Space is always an excuse to break a line
  404.                             cpCurrent++;    // Goto next character
  405.                             break;
  406.         }
  407.         if( PageInfo.dwCurLineWidth > ParagraphInfo.dwWidth && (cpStart != cpEnd)) // Wrap Line
  408.         {
  409.             *cpEnd = 0;        // Set end of string to null
  410.  
  411.             TextOutAtCurPos((LPSTR)cpStart);
  412.  
  413.             // Next Line Down
  414.             PageInfo.ptCurrentPos.y += ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading;
  415.             if(PageInfo.ptCurrentPos.y > PrinterInfo.ptPageSize.y - PrinterInfo.rcMargins.bottom - ParagraphInfo.tm.tmHeight - ParagraphInfo.tm.tmExternalLeading)
  416.             {
  417.                 EjectPage();
  418.             }
  419.             // Start at left margin
  420.             PageInfo.ptCurrentPos.x = PrinterInfo.rcMargins.left + ParagraphInfo.nLeftIndent;
  421.  
  422.             cpStart = cpCurrent = cpEnd+1;        // Set everything to start of next line
  423.             PageInfo.dwCurLineWidth = 0;        // Clear Width
  424.         }
  425.     }
  426. showline:
  427.     if(*cpStart)            // No Text, so don't print it
  428.     {
  429.  
  430.         TextOutAtCurPos((LPSTR) cpStart);
  431.  
  432.         PageInfo.ptCurrentPos.x += (int)PageInfo.dwCurLineWidth;    // Set current X position
  433.  
  434.     }
  435.     else                    // We still have to put the border around the current line
  436.     {
  437.         if(ParagraphInfo.nStyle & LEFT_BORDER)        // Left border
  438.             FDrawLine(    ppPrinter.hDC,
  439.                         PrinterInfo.rcMargins.left - (int)((HIBYTE(ParagraphInfo.wBorderWidth))),
  440.                         PageInfo.ptCurrentPos.y - (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2),
  441.                         PrinterInfo.rcMargins.left - (int)((HIBYTE(ParagraphInfo.wBorderWidth))),
  442.                         PageInfo.ptCurrentPos.y + ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading + (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2));
  443.  
  444.         if(ParagraphInfo.nStyle & RIGHT_BORDER)        // Right border
  445.             FDrawLine(    ppPrinter.hDC,
  446.                         PrinterInfo.ptPageSize.x - PrinterInfo.rcMargins.right + (int)((HIBYTE(ParagraphInfo.wBorderWidth))),
  447.                         PageInfo.ptCurrentPos.y - (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2),
  448.                         PrinterInfo.ptPageSize.x - PrinterInfo.rcMargins.right + (int)((HIBYTE(ParagraphInfo.wBorderWidth))),
  449.                         PageInfo.ptCurrentPos.y + ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading + (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2));
  450.  
  451.     }
  452.  
  453.     GlobalUnlock(hText);
  454.     GlobalFree(hText);
  455.  
  456.     return TRUE;
  457. }
  458.  
  459. /*************************************************************************
  460.     Clean up after printing a paragraph of text
  461. *************************************************************************/
  462.  
  463. int    FAR PASCAL    FinishParagraph(void)
  464. {
  465.  
  466.     SelectObject(ppPrinter.hDC, ParagraphInfo.hOldFont);
  467.     DeleteObject(ParagraphInfo.hFont);
  468.  
  469.     // Next Line Down
  470.     PageInfo.ptCurrentPos.y += ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading;
  471.  
  472.     // Bottom Border Line
  473.     if(ParagraphInfo.nStyle & BOTTOM_BORDER)
  474.         FDrawLine(    ppPrinter.hDC,
  475.                     PrinterInfo.rcMargins.left - (int)(HIBYTE(ParagraphInfo.wBorderWidth)),
  476.                     PageInfo.ptCurrentPos.y + (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2),
  477.                     PrinterInfo.ptPageSize.x - PrinterInfo.rcMargins.right + (int)(HIBYTE(ParagraphInfo.wBorderWidth)),
  478.                     PageInfo.ptCurrentPos.y + (int)(LOBYTE(ParagraphInfo.wBorderWidth)/2));
  479.  
  480.     if((PageInfo.ptCurrentPos.y += ParagraphInfo.nSpaceAfter) > (PrinterInfo.ptPageSize.y - PrinterInfo.rcMargins.bottom))
  481.     {
  482.         EjectPage();        // Sets current positon too
  483.     }
  484.  
  485.     if(PageInfo.ptCurrentPos.y > PrinterInfo.ptPageSize.y - PrinterInfo.rcMargins.bottom - ParagraphInfo.tm.tmHeight - ParagraphInfo.tm.tmExternalLeading)
  486.     {
  487.         EjectPage();
  488.     }
  489.     // Start at left margin
  490.     PageInfo.ptCurrentPos.x = PrinterInfo.rcMargins.left + ParagraphInfo.nLeftIndent;
  491.  
  492.     return TRUE;
  493. }
  494.  
  495. /*************************************************************************
  496.     Internal function to print a line of text at a specific position.
  497. *************************************************************************/
  498.  
  499. int TextOutAtCurPos(LPSTR szText)
  500. {
  501.     RECT    rc;
  502.     int        nRetVal;
  503.  
  504.     if(ParagraphInfo.nStyle & LEFT_BORDER)        // Left border
  505.         FDrawLine(    ppPrinter.hDC,
  506.                     PrinterInfo.rcMargins.left - (int)(HIBYTE(ParagraphInfo.wBorderWidth)),
  507.                     PageInfo.ptCurrentPos.y - (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2),
  508.                     PrinterInfo.rcMargins.left - (int)(HIBYTE(ParagraphInfo.wBorderWidth)),
  509.                     PageInfo.ptCurrentPos.y + ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading + (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2));
  510.  
  511.     if(ParagraphInfo.nStyle & RIGHT_BORDER)        // Right border
  512.         FDrawLine(    ppPrinter.hDC,
  513.                     PrinterInfo.ptPageSize.x - PrinterInfo.rcMargins.right + (int)(HIBYTE(ParagraphInfo.wBorderWidth)),
  514.                     PageInfo.ptCurrentPos.y - (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2),
  515.                     PrinterInfo.ptPageSize.x - PrinterInfo.rcMargins.right + (int)(HIBYTE(ParagraphInfo.wBorderWidth)),
  516.                     PageInfo.ptCurrentPos.y + ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading + (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2));
  517.  
  518.     SetRect((LPRECT)&rc,
  519.             (int)PageInfo.ptCurrentPos.x     -     PrinterInfo.rcUnprintable.left,
  520.             (int)PageInfo.ptCurrentPos.y     -     PrinterInfo.rcUnprintable.top,
  521.             (int)PrinterInfo.ptPageSize.x     -     PrinterInfo.rcMargins.right     -     PrinterInfo.rcUnprintable.left,
  522.             (int)PageInfo.ptCurrentPos.y     -     PrinterInfo.rcUnprintable.top     +    ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading);
  523.  
  524.     nRetVal = ExtTextOut(    ppPrinter.hDC,
  525.                             PageInfo.ptCurrentPos.x - PrinterInfo.rcUnprintable.left,
  526.                             PageInfo.ptCurrentPos.y - PrinterInfo.rcUnprintable.top,
  527.                             ETO_OPAQUE,
  528.                             (LPRECT)&rc,
  529.                             szText,
  530.                             lstrlen(szText),
  531.                             NULL);
  532.     return nRetVal;
  533. }
  534.  
  535. /*************************************************************************
  536.     Draw an Ellipse
  537. *************************************************************************/
  538. int FDrawEllipse(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY)
  539. {
  540.     int nRet=FALSE;
  541.     HPEN hPen, hOldPen;
  542.  
  543.     // Black Pen
  544.     hPen = CreatePen(0,LOBYTE(ParagraphInfo.wBorderWidth),0);
  545.  
  546.     if(hPen)
  547.     {
  548.         hOldPen = SelectObject(hDC, hPen);
  549.  
  550.         nRet = Ellipse(    hDC,
  551.                         nStartX - PrinterInfo.rcUnprintable.left,
  552.                         nStartY - PrinterInfo.rcUnprintable.top,
  553.                         nEndX - PrinterInfo.rcUnprintable.left,
  554.                         nEndY - PrinterInfo.rcUnprintable.top);
  555.  
  556.         SelectObject(hDC, hOldPen);
  557.         DeleteObject(hPen);
  558.     }
  559.  
  560.     return nRet;
  561. }
  562.  
  563.  
  564. /*************************************************************************
  565.     Draw a Rectangele with Rounded Corners
  566. *************************************************************************/
  567. int FDrawRndRectangle(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY, int nElpX, int nElpY)
  568. {
  569.     int nRet=FALSE;
  570.     HPEN hPen, hOldPen;
  571.  
  572.     // Black Pen
  573.     hPen = CreatePen(0,LOBYTE(ParagraphInfo.wBorderWidth),0);
  574.  
  575.     if(hPen)
  576.     {
  577.         hOldPen = SelectObject(hDC, hPen);
  578.  
  579.         nRet = RoundRect(    hDC,
  580.                             nStartX - PrinterInfo.rcUnprintable.left,
  581.                             nStartY - PrinterInfo.rcUnprintable.top,
  582.                             nEndX - PrinterInfo.rcUnprintable.left,
  583.                             nEndY - PrinterInfo.rcUnprintable.top,
  584.                             nElpX,
  585.                             nElpY);
  586.         SelectObject(hDC, hOldPen);
  587.         DeleteObject(hPen);
  588.     }
  589.  
  590.     return nRet;
  591. }
  592.  
  593. /*************************************************************************
  594.     Draw a Rectangle with Square Corners
  595. *************************************************************************/
  596. int FDrawRectangle(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY)
  597. {
  598.     int nRet=FALSE;
  599.     HPEN hPen, hOldPen;
  600.  
  601.     // Black Pen
  602.     hPen = CreatePen(0,LOBYTE(ParagraphInfo.wBorderWidth),0);
  603.  
  604.     if(hPen)
  605.     {
  606.         hOldPen = SelectObject(hDC, hPen);
  607.  
  608.         nRet = Rectangle(    hDC,
  609.                             nStartX - PrinterInfo.rcUnprintable.left,
  610.                             nStartY - PrinterInfo.rcUnprintable.top,
  611.                             nEndX - PrinterInfo.rcUnprintable.left,
  612.                             nEndY - PrinterInfo.rcUnprintable.top);
  613.         SelectObject(hDC, hOldPen);
  614.         DeleteObject(hPen);
  615.     }
  616.  
  617.     return nRet;
  618. }
  619.  
  620. /*************************************************************************
  621.     Draw a line
  622. *************************************************************************/
  623. int    FDrawLine(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY)
  624. {
  625.     int nRet=FALSE;
  626.     HPEN    hPen, hOldPen;
  627.  
  628.     hPen = CreatePen(0,LOBYTE(ParagraphInfo.wBorderWidth),0);
  629.  
  630.     if(hPen)
  631.     {
  632.         hOldPen = SelectObject(hDC, hPen);
  633.  
  634.         MoveTo(    hDC,
  635.                 nStartX - PrinterInfo.rcUnprintable.left,
  636.                 nStartY - PrinterInfo.rcUnprintable.top);
  637.         nRet = LineTo(    hDC,
  638.                         (int)nEndX - PrinterInfo.rcUnprintable.left,
  639.                         (int)nEndY - PrinterInfo.rcUnprintable.top);
  640.  
  641.         SelectObject(hDC, hOldPen);
  642.         DeleteObject(hPen);
  643.     }
  644.  
  645.     return nRet;
  646. }
  647.  
  648. /*************************************************************************
  649.     Print a Headline which is just a special case of a paragraph,
  650.     makes all setup and clean up calls for you.
  651. *************************************************************************/
  652. int    FAR PASCAL     PrintHeadline(LPSTR szHeadLine, LPSTR szFontName, int nFontSize, int nStyle)
  653. {
  654.  
  655.     StartParagraph(szFontName, nFontSize, nStyle);
  656.     ParagraphText(szHeadLine);
  657.     FinishParagraph();
  658.  
  659.     return TRUE;
  660. }
  661.  
  662. /*************************************************************************
  663.     End of printing function, cleans up memory and ejects the last page
  664. *************************************************************************/
  665.  
  666. int FAR PASCAL DonePrinting(void)
  667. {
  668.     int nRet=FALSE;
  669.  
  670.     Escape(ppPrinter.hDC,NEWFRAME, 0, 0L, 0L);            // Kick out last page
  671.     Escape(ppPrinter.hDC,ENDDOC, 0, 0L, 0L);
  672.  
  673.     FreeProcInstance(lpfnAbortProc);
  674.  
  675.     nRet = DeleteDC(ppPrinter.hDC);
  676.        if (ppPrinter.hDevMode != NULL)
  677.        {
  678.         GlobalFree(ppPrinter.hDevMode);
  679.         ppPrinter.hDevMode = NULL;
  680.        }
  681.        if (ppPrinter.hDevNames != NULL)
  682.        {
  683.         GlobalFree(ppPrinter.hDevNames);
  684.         ppPrinter.hDevNames = NULL;
  685.        }
  686.  
  687.     return nRet;
  688.  
  689. }
  690.  
  691. /*************************************************************************
  692.     Unconditionally ejects page from printer, then sets the current page
  693.     position to upper left corner, this also restores the currently
  694.     selected font.
  695. *************************************************************************/
  696.  
  697. int    FAR PASCAL    EjectPage(void)
  698. {
  699.     int nRet;
  700.     HFONT hFont;
  701.  
  702.     // Save Currently selected Font
  703.     hFont = SelectObject(ppPrinter.hDC, GetStockObject(DEVICE_DEFAULT_FONT));
  704.  
  705.     nRet = Escape(ppPrinter.hDC,NEWFRAME, 0, 0L, 0L);            // Kick out page
  706.  
  707.     // Restore Currently select Font
  708.     SelectObject(ppPrinter.hDC, hFont);
  709.  
  710.     PageInfo.ptCurrentPos.x = PrinterInfo.rcMargins.left;        // Start at upper left hand corner
  711.     PageInfo.ptCurrentPos.y = PrinterInfo.rcMargins.top;
  712.  
  713.     PageInfo.bPageDirty = FALSE;                                // Page is no longer dirty
  714.  
  715.     return nRet;
  716.  
  717. }
  718.  
  719. /*************************************************************************
  720.     Sets margins for pages printed after this function is called.
  721. *************************************************************************/
  722.  
  723. int FAR PASCAL PageLayoutSetup(int nTop, int nRight, int nBottom, int nLeft)
  724. {
  725.  
  726.     nTop = min(nTop, 2 * INCH);            // No bigger than
  727.     nTop = max(nTop, 0);                // No smaller than
  728.  
  729.     nBottom = min(nBottom, 2 * INCH);     // No bigger than
  730.     nBottom = max(nBottom, 0);            // No smaller than
  731.  
  732.     nLeft = min(nLeft, 2 * INCH);        // No bigger than
  733.     nLeft = max(nLeft, 0);                // No smaller than
  734.  
  735.     nRight = min(nRight, 2 * INCH);     // No bigger than
  736.     nRight = max(nRight, 0);            // No smaller than
  737.  
  738.     PrinterInfo.rcMargins.top        = (int)(nTop    * (int)(PrinterInfo.ptResolution.y * 0.01));
  739.     PrinterInfo.rcMargins.bottom    = (int)(nBottom * (int)(PrinterInfo.ptResolution.y * 0.01));
  740.     PrinterInfo.rcMargins.left        = (int)(nLeft    * (int)(PrinterInfo.ptResolution.x * 0.01));
  741.     PrinterInfo.rcMargins.right     = (int)(nRight    * (int)(PrinterInfo.ptResolution.x * 0.01));
  742.  
  743.     PageInfo.ptCurrentPos.x = PrinterInfo.rcMargins.left;        // Start at upper left hand corner
  744.     PageInfo.ptCurrentPos.y = PrinterInfo.rcMargins.top;
  745.  
  746.     return TRUE;
  747. }
  748.  
  749.  
  750. /*************************************************************************
  751.     This procedure brings up a message box with Common Dialog error text
  752. *************************************************************************/
  753.  
  754. BOOL DoCommDlgError(HWND hWnd, DWORD dwError)
  755. {
  756.     char sz1[80];
  757.     char sz2[32];
  758.  
  759.     if(dwError != 0)
  760.     {
  761.         LoadString(hInst, (WORD)dwError, sz2, 32);
  762.  
  763.         if(!sz2[0])
  764.             lstrcpy(sz2,"Unknown");
  765.  
  766.         wsprintf(sz1," Error: %s ",(LPSTR)sz2);
  767.  
  768.         MessageBox(hWnd,sz1," COMMDLG.DLL ERROR ",MB_ICONSTOP);
  769.         return TRUE;
  770.     }
  771.     else
  772.         return FALSE;
  773.  
  774. }
  775.  
  776. /*************************************************************************
  777.     Fills the PrinterInfo structure with the printers current
  778.     unprintable region
  779. *************************************************************************/
  780.  
  781. BOOL GetUnprintableRegion(HDC hDCPrn)
  782. {
  783.     RECT     rcTemp;
  784.     POINT     ptPhysPageSize;
  785.     POINT     ptOffset;
  786.  
  787.     Escape(hDCPrn, GETPHYSPAGESIZE, NULL, (LPSTR)NULL, (LPSTR) &ptPhysPageSize);
  788.     Escape(hDCPrn, GETPRINTINGOFFSET, NULL, (LPSTR)NULL, (LPSTR) &ptOffset);
  789.     GetClipBox(hDCPrn,&rcTemp);        // Size of Printable region
  790.  
  791.     PrinterInfo.ptPageSize.x            = ptPhysPageSize.x;
  792.     PrinterInfo.ptPageSize.y            = ptPhysPageSize.y;
  793.     PrinterInfo.rcUnprintable.top         = ptOffset.y;
  794.     PrinterInfo.rcUnprintable.left        = ptOffset.x;
  795.     PrinterInfo.rcUnprintable.right        = ptPhysPageSize.x - ptOffset.x;
  796.     PrinterInfo.rcUnprintable.bottom    = ptPhysPageSize.y - ptOffset.y;
  797.  
  798.     return TRUE;
  799.  
  800. }
  801.  
  802. /*************************************************************************
  803.     Sticks the printers current resolution in the PrinterInfo Structure
  804. *************************************************************************/
  805.  
  806. BOOL GetPrinterResolution(HDC hDCPrn)
  807. {
  808.     PrinterInfo.ptResolution.x = GetDeviceCaps(hDCPrn, LOGPIXELSX);
  809.     PrinterInfo.ptResolution.y = GetDeviceCaps(hDCPrn, LOGPIXELSY);
  810.  
  811.     return TRUE;
  812. }
  813.  
  814. /*************************************************************************
  815.     Abort Proc for printing, this is where control is returned to the
  816.     system during printing.  Gets called by the printer driver
  817.     periocically for control release purposes.
  818. *************************************************************************/
  819.  
  820. BOOL FAR PASCAL PrnAbortProc(HDC hDCPrn, short nCode)
  821. {
  822.     MSG msg;
  823.  
  824.     while(!fAbort && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  825.     {
  826.         {
  827.             TranslateMessage(&msg);
  828.             DispatchMessage(&msg);
  829.         }
  830.     }
  831.  
  832.     return !fAbort;
  833. }
  834.  
  835. /*************************************************************************
  836.     Returns version number of the Print DLL
  837. *************************************************************************/
  838.  
  839. int FAR PASCAL PrintDLLVersion(VOID)
  840. {
  841.     return ((MAJOR_VERSION) | (MINOR_VERSION << 8));
  842.  
  843. }
  844.  
  845.  
  846. /*************************************************************************
  847.     Sets the space before and after a paragraph
  848. *************************************************************************/
  849. BOOL    FAR PASCAL SetParagraphSpacing(int nSpaceBefore, int nSpaceAfter)
  850. {
  851.  
  852.     // Check for bogus Spacing size values
  853.     nSpaceBefore = min(nSpaceBefore, MAX_FONT_SIZE);    // No bigger than
  854.     nSpaceBefore = max(nSpaceBefore, MIN_FONT_SIZE);    // No smaller than
  855.  
  856.     ParagraphInfo.nSpaceBefore = (int)((PrinterInfo.ptResolution.y * nSpaceBefore) / 72);
  857.  
  858.     // Check for bogus Spacing size values
  859.     nSpaceAfter = min(nSpaceAfter, MAX_FONT_SIZE);        // No bigger than
  860.     nSpaceAfter = max(nSpaceAfter, MIN_FONT_SIZE);        // No smaller than
  861.  
  862.     ParagraphInfo.nSpaceAfter = (int)((PrinterInfo.ptResolution.y * nSpaceAfter) / 72);
  863.  
  864.     return TRUE;
  865. }
  866.  
  867.  
  868. /*************************************************************************
  869.     Sets Line Weight for borders
  870. *************************************************************************/
  871. BOOL    FAR PASCAL SetBorderWidth(int nWidth)
  872. {
  873.     if(nWidth !=0)
  874.     {
  875.         // Check for bogus Width values
  876.         nWidth = min(nWidth, MAX_WIDTH_SIZE);        // No bigger than
  877.         nWidth = max(nWidth, MIN_WIDTH_SIZE);        // No smaller than
  878.  
  879.         ParagraphInfo.wBorderWidth =  (WORD)(((PrinterInfo.ptResolution.x * nWidth) / 72) << 8);
  880.         ParagraphInfo.wBorderWidth += (WORD)((PrinterInfo.ptResolution.y * nWidth) / 72);
  881.     }
  882.     else    // Gaurentee 1 pixel width
  883.     {
  884.         ParagraphInfo.wBorderWidth =  (WORD)((1) << 8);
  885.         ParagraphInfo.wBorderWidth += (WORD)(1);
  886.  
  887.     }
  888.     return TRUE;
  889. }
  890.  
  891. /*************************************************************************
  892.     Prints headers for a set of columns
  893. *************************************************************************/
  894. int        FAR PASCAL PrintColumnHeaders(LPSTR szHeader, int nNumColumns, LPINT nC, LPSTR szFontName, int nFontSize, int nStyle)
  895. {
  896.     SetUpColumns(nNumColumns, nC, szFontName, nFontSize, nStyle);
  897.     PrintColumnText(szHeader);
  898.     EndColumnPrinting();
  899.  
  900.     return TRUE;
  901.  
  902. }
  903. /*************************************************************************
  904.     Sets up the number and widths of columns to be printed
  905. *************************************************************************/
  906. int        FAR PASCAL SetUpColumns(int nNumColumns, LPINT nC, LPSTR szFontName, int nFontSize, int nStyle)
  907. {
  908.     int nFontWeight;        // Weight of the font
  909.     BYTE bFontItalic;        // Italic flag
  910.  
  911.     // Remember these
  912.     ColumnInfo.nNumColumns = nNumColumns;
  913.     ColumnInfo.rgColumnWidths[0] = nC[0];
  914.     ColumnInfo.rgColumnWidths[1] = nC[1];
  915.     ColumnInfo.rgColumnWidths[2] = nC[2];
  916.     ColumnInfo.rgColumnWidths[3] = nC[3];
  917.     ColumnInfo.rgColumnWidths[4] = nC[4];
  918.     ColumnInfo.rgColumnWidths[5] = nC[5];
  919.     ColumnInfo.rgColumnWidths[6] = nC[6];
  920.     ColumnInfo.rgColumnWidths[7] = nC[7];
  921.  
  922.     // Check for bogus font size values
  923.     nFontSize = min(nFontSize, MAX_FONT_SIZE);        // No bigger than
  924.     nFontSize = max(nFontSize, MIN_FONT_SIZE);        // No smaller than
  925.  
  926.     // Get weight of font
  927.     if(nStyle & BOLD_FONT)     nFontWeight = FW_BOLD;
  928.     else                     nFontWeight = FW_NORMAL;
  929.  
  930.     // Get font slant
  931.     if(nStyle & ITALIC_FONT)    bFontItalic = 1;
  932.     else                        bFontItalic = 0;
  933.  
  934.     // Remember Border Style and Size
  935.     ColumnInfo.nStyle = nStyle;
  936.     ColumnInfo.wBorderWidth =  (WORD)(((PrinterInfo.ptResolution.x * BORDER_WIDTH) / 72) << 8);
  937.     ColumnInfo.wBorderWidth += (WORD)((PrinterInfo.ptResolution.y * BORDER_WIDTH) / 72);
  938.  
  939.     // Setup Text Attributes
  940.     SetBkMode(ppPrinter.hDC, TRANSPARENT);            // Show whatever was there before through the text
  941.     SetTextColor(ppPrinter.hDC, 0);                    // Black Text
  942.     SetBkColor(ppPrinter.hDC, 0x00FFFFFF);            // White Background
  943.     SetTextAlign(ppPrinter.hDC, TA_TOP|TA_LEFT);    // Text aligned at top, left of bounding box
  944.  
  945.     ColumnInfo.hFont = CreateFont((int)((PrinterInfo.ptResolution.y * nFontSize) / 72),
  946.                                        0, 0, 0,
  947.                                        nFontWeight,
  948.                                        bFontItalic,
  949.                                        0, 0,
  950.                                        ANSI_CHARSET,
  951.                                        OUT_DEFAULT_PRECIS,
  952.                                        CLIP_DEFAULT_PRECIS,
  953.                                        DEFAULT_QUALITY,
  954.                                        VARIABLE_PITCH | FF_DONTCARE,
  955.                                        szFontName);
  956.     if(ColumnInfo.hFont)    // If we get the font, selected and get the metrics and width
  957.     {
  958.         ColumnInfo.hOldFont = SelectObject(ppPrinter.hDC, ColumnInfo.hFont);
  959.         GetTextMetrics(ppPrinter.hDC, (LPTEXTMETRIC)&ColumnInfo.tm);
  960.         GetCharWidth(ppPrinter.hDC, FIRST_CHAR, LAST_CHAR, (LPINT)&ColumnInfo.nWidth);
  961.     }
  962.  
  963.     return TRUE;
  964. }
  965.  
  966. /*************************************************************************
  967.     Printed text in columns, the text is seperated by
  968.     tab (0x09) characters
  969. *************************************************************************/
  970. int        FAR PASCAL PrintColumnText(LPSTR szText)
  971. {
  972.     int     nColumnCount;
  973.     int     nMaxRowHeight;
  974.     int        nLineCount;
  975.     int        nSpaceCount;
  976.     int     nOffset;
  977.     RECT    rc;
  978.     char FAR    *cpColText;
  979.     char FAR    *cpBegin;
  980.     char FAR    *cpCurrent;
  981.     char FAR    *rgcpColText[MAX_COLUMNS];
  982.     int        nColCount;
  983.     DWORD    dwWidth, dwColumnWidth;
  984.     HGLOBAL    hText;
  985.     LPSTR    lpText;
  986.  
  987.     PageInfo.bPageDirty = TRUE;
  988.  
  989.     // Get our own private copy of the text
  990.     hText = GlobalAlloc(GHND, lstrlen((LPSTR)szText)+1);
  991.  
  992.     if(!hText) return FALSE;
  993.  
  994.     lpText = (LPSTR)GlobalLock(hText);
  995.  
  996.     if(!lpText) return FALSE;
  997.  
  998.     lstrcpy((LPSTR)lpText, (LPSTR)szText);
  999.  
  1000.     // Calculate where all the strings are
  1001.     cpColText = (LPSTR)lpText;
  1002.     nColCount = 0;
  1003.     rgcpColText[nColCount++] = (LPSTR)cpColText;        // First Column;
  1004.  
  1005.     // Setup pointers to each column of text
  1006.     while(*cpColText != NULL)
  1007.     {
  1008.         if(*cpColText == '\t')
  1009.         {
  1010.             *cpColText = NULL;                    // NULL Terminate
  1011.             cpColText++;
  1012.             rgcpColText[nColCount++] = (LPSTR)cpColText;
  1013.         }
  1014.         else
  1015.         {
  1016.             cpColText++;
  1017.         }
  1018.  
  1019.     }
  1020.  
  1021.     // Calculate the Max Height of the cells
  1022.     nMaxRowHeight = 1;
  1023.  
  1024.     for(nColumnCount = 0; nColumnCount < ColumnInfo.nNumColumns; nColumnCount++)
  1025.     {
  1026.         cpBegin = cpCurrent = rgcpColText[nColumnCount];
  1027.         dwColumnWidth = (DWORD)(ColumnInfo.rgColumnWidths[nColumnCount] * (PrinterInfo.ptResolution.x * 0.01));
  1028.         dwWidth = 0;
  1029.         nSpaceCount = -1;
  1030.         nLineCount = 1;
  1031.  
  1032.         while(*cpCurrent != NULL)
  1033.         {
  1034.  
  1035.             dwWidth += ColumnInfo.nWidth[(int)(*cpCurrent) - FIRST_CHAR];        // Width of Character
  1036.             switch(*cpCurrent)
  1037.             {
  1038.                 case ' ' :  if(dwWidth > dwColumnWidth)
  1039.                             {
  1040.                                  nLineCount++;
  1041.                                  if(nSpaceCount >= 0)
  1042.                                  {
  1043.                                      cpCurrent = cpBegin;
  1044.                                      nSpaceCount = -1;
  1045.                                  }
  1046.                                  else
  1047.                                      cpCurrent++;
  1048.                                  dwWidth = 0;
  1049.  
  1050.                             }
  1051.                             else
  1052.                             {
  1053.                                 nSpaceCount++;
  1054.                                 cpBegin = ++cpCurrent;
  1055.                             }
  1056.                             break;
  1057.                 case '\r':    cpBegin = ++cpCurrent;
  1058.                             nLineCount++;
  1059.                             break;
  1060.                 default     :  cpCurrent++;
  1061.                             break;
  1062.  
  1063.             }
  1064.  
  1065.  
  1066.         }
  1067.         if(dwWidth > dwColumnWidth) nLineCount++;        // In case of any left overs
  1068.  
  1069.         nMaxRowHeight = max(nMaxRowHeight, nLineCount);
  1070.     }
  1071.  
  1072.     nMaxRowHeight *= ColumnInfo.tm.tmHeight;
  1073.  
  1074.     // See if first line will fit on page
  1075.     if((PageInfo.ptCurrentPos.y + nMaxRowHeight) > (PrinterInfo.ptPageSize.y - PrinterInfo.rcMargins.top - PrinterInfo.rcMargins.bottom))
  1076.     {
  1077.         EjectPage();        // Sets current positon too
  1078.     }
  1079.  
  1080.     SetBorderWidth(0);
  1081.  
  1082.  
  1083.     for(nColumnCount = 0; nColumnCount < ColumnInfo.nNumColumns; nColumnCount++)
  1084.     {
  1085.         nOffset = GetColumnOffset(nColumnCount);
  1086.  
  1087.         SetRect(    &rc,
  1088.                     PrinterInfo.rcMargins.left + nOffset,
  1089.                     PageInfo.ptCurrentPos.y,
  1090.                     PrinterInfo.rcMargins.left + nOffset + (int)(ColumnInfo.rgColumnWidths[nColumnCount] * (PrinterInfo.ptResolution.x * 0.01)),
  1091.                     PageInfo.ptCurrentPos.y + nMaxRowHeight);
  1092.  
  1093.         if(ColumnInfo.nStyle & TOP_BORDER)
  1094.         {
  1095.             // Draw Top Border
  1096.             FDrawLine(ppPrinter.hDC, rc.left, rc.top, rc.right, rc.top);
  1097.         }
  1098.  
  1099.         if(ColumnInfo.nStyle & LEFT_BORDER)
  1100.         {
  1101.             // Draw Left Border
  1102.             FDrawLine(ppPrinter.hDC, rc.left, rc.top, rc.left, rc.bottom);
  1103.         }
  1104.  
  1105.         if(ColumnInfo.nStyle & RIGHT_BORDER)
  1106.         {
  1107.             // Draw Right Border
  1108.             FDrawLine(ppPrinter.hDC, rc.right, rc.top, rc.right, rc.bottom);
  1109.         }
  1110.  
  1111.         if(ColumnInfo.nStyle & BOTTOM_BORDER)
  1112.         {
  1113.             // Draw Bottom Border
  1114.             FDrawLine(ppPrinter.hDC, rc.left, rc.bottom, rc.right, rc.bottom);
  1115.         }
  1116.  
  1117.         rc.left     += 1;        // Get Text Within Borders
  1118.         rc.top      += 1;
  1119.         rc.right     -= 1;
  1120.         rc.bottom     -= 1;
  1121.  
  1122.         CellDrawText(ppPrinter.hDC, (LPSTR)rgcpColText[nColumnCount], (LPRECT)&rc);
  1123.  
  1124.     }
  1125.  
  1126.     PageInfo.ptCurrentPos.y += nMaxRowHeight;
  1127.  
  1128.     GlobalUnlock(hText);
  1129.     GlobalFree(hText);
  1130.  
  1131.     return TRUE;
  1132. }
  1133.  
  1134.  
  1135. /*************************************************************************
  1136.     Ends column printing and does cleanup
  1137. *************************************************************************/
  1138. int        FAR PASCAL EndColumnPrinting(VOID)
  1139. {
  1140.     SelectObject(ppPrinter.hDC, ColumnInfo.hOldFont);
  1141.     DeleteObject(ColumnInfo.hFont);
  1142.  
  1143.     return TRUE;
  1144. }
  1145.  
  1146. /*************************************************************************
  1147.     Calculates the Left Offset of the given column from the left
  1148.     edge of the first column
  1149. *************************************************************************/
  1150. int    GetColumnOffset(int nColumn)
  1151. {
  1152.      int nOffset=0;
  1153.      int nTemp;
  1154.  
  1155.      if(nColumn == 0) return nOffset;
  1156.  
  1157.     for(nTemp=0; nTemp < nColumn; nTemp++)
  1158.     {
  1159.         nOffset += (int)(ColumnInfo.rgColumnWidths[nTemp] * (PrinterInfo.ptResolution.x * 0.01));
  1160.     }
  1161.  
  1162.     return nOffset;
  1163. }
  1164.  
  1165. /*************************************************************************
  1166.     Prints Text on Physical page given logical co-ordinates
  1167. *************************************************************************/
  1168. int CellDrawText(HDC hDC, LPSTR szText, LPRECT rc)
  1169. {
  1170.     RECT rcTemp;
  1171.  
  1172.     rcTemp.top         = rc->top         - PrinterInfo.rcUnprintable.top;
  1173.     rcTemp.bottom     = rc->bottom     - PrinterInfo.rcUnprintable.top;
  1174.     rcTemp.left     = rc->left         - PrinterInfo.rcUnprintable.left;
  1175.     rcTemp.right     = rc->right     - PrinterInfo.rcUnprintable.left;
  1176.  
  1177.     DrawText(hDC, (LPSTR)szText, lstrlen((LPSTR)szText), (LPRECT)&rcTemp, DT_TOP | DT_WORDBREAK);
  1178.  
  1179.     return TRUE;
  1180. }
  1181.  
  1182. /*************************************************************************
  1183.     Internal function to retrieve the Device Context of the current
  1184.     Printer Driver
  1185. *************************************************************************/
  1186.  
  1187. HDC        GetPrinterDC(void)
  1188. {
  1189.     static char szPrinter[80];
  1190.     char *szDevice, *szDriver, *szOutput;
  1191.  
  1192.     GetProfileString("windows", "device",",,,",szPrinter, 80);
  1193.  
  1194.     if(    (szDevice = strtok(szPrinter,"," )) &&
  1195.         (szDriver = strtok(NULL,     ", ")) &&
  1196.         (szOutput = strtok(NULL,     ", ")))
  1197.     {
  1198.         return CreateDC(szDriver, szDevice, szOutput, NULL);
  1199.     }
  1200.  
  1201.     return FALSE;
  1202. }
  1203.  
  1204. /*************************************************************************
  1205.     Unconditionally kills the current print job
  1206. *************************************************************************/
  1207. BOOL FAR PASCAL KillJob(void)
  1208. {
  1209.  
  1210.     fAbort = TRUE;
  1211.  
  1212.     return fAbort;
  1213.  
  1214. }
  1215.  
  1216. /*************************************************************************
  1217.      Returns the name of the current Printer
  1218. *************************************************************************/
  1219. BOOL FAR PASCAL PrinterName(LPSTR szDevName)
  1220. {
  1221.     DEVMODE FAR *lpDevmode;
  1222.  
  1223.     /* Initialize the necessary PRINTDLG structure members. */
  1224.  
  1225.     ppPrinter.lStructSize = sizeof(PRINTDLG);
  1226.     ppPrinter.Flags = PD_RETURNDEFAULT;
  1227.  
  1228.     if(ppPrinter.hDevMode)
  1229.     {
  1230.         lpDevmode = (DEVMODE FAR *)GlobalLock(ppPrinter.hDevMode);
  1231.         lstrcpy(szDevName,(LPSTR)lpDevmode->dmDeviceName);
  1232.         GlobalUnlock(ppPrinter.hDevMode);
  1233.         return TRUE;
  1234.     }
  1235.     if (PrintDlg(&ppPrinter) != 0)
  1236.     {
  1237.         lpDevmode = (DEVMODE FAR *)GlobalLock(ppPrinter.hDevMode);
  1238.         lstrcpy(szDevName,(LPSTR)lpDevmode->dmDeviceName);
  1239.         GlobalUnlock(ppPrinter.hDevMode);
  1240.         return TRUE;
  1241.     }
  1242.     else
  1243.     {
  1244.         DoCommDlgError(hWndApp, CommDlgExtendedError());
  1245.         return FALSE;
  1246.     }
  1247. }
  1248.  
  1249. /*************************************************************************
  1250.     Returns the port to which the current printer is connected
  1251. *************************************************************************/
  1252. BOOL FAR PASCAL PrinterPort(LPSTR szPortName)
  1253. {
  1254.     DEVNAMES FAR *lpDevnames;
  1255.  
  1256.     // Initialize the necessary PRINTDLG structure members.
  1257.  
  1258.     ppPrinter.lStructSize = sizeof(PRINTDLG);
  1259.     ppPrinter.Flags = PD_RETURNDEFAULT;
  1260.  
  1261.     if(ppPrinter.hDevNames)
  1262.     {
  1263.         lpDevnames = (DEVNAMES FAR *)GlobalLock(ppPrinter.hDevNames);
  1264.         lstrcpy(szPortName,(LPSTR)lpDevnames + lpDevnames->wOutputOffset);
  1265.         GlobalUnlock(ppPrinter.hDevNames);
  1266.         return TRUE;
  1267.     }
  1268.     if (PrintDlg(&ppPrinter) != 0)
  1269.     {
  1270.         lpDevnames = (DEVNAMES FAR *)GlobalLock(ppPrinter.hDevNames);
  1271.         lstrcpy(szPortName,(LPSTR)lpDevnames + lpDevnames->wOutputOffset);
  1272.         GlobalUnlock(ppPrinter.hDevNames);
  1273.         return TRUE;
  1274.     }
  1275.     else
  1276.     {
  1277.         DoCommDlgError(hWndApp, CommDlgExtendedError());
  1278.         return FALSE;
  1279.     }
  1280. }
  1281.  
  1282. /*************************************************************************
  1283. Returns TRUE if there are objects on the page, FALSE if the page is
  1284. empty.
  1285. *************************************************************************/
  1286. BOOL FAR PASCAL IsPageDirty(void)
  1287. {
  1288.     return PageInfo.bPageDirty;
  1289.  
  1290. }
  1291.  
  1292. /*************************************************************************
  1293. Returns the current Vertical cursor location in TWIPS
  1294. *************************************************************************/
  1295. int FAR PASCAL PagePosY(void)
  1296. {
  1297.  
  1298.     return ((PageInfo.ptCurrentPos.y/PrinterInfo.ptResolution.y)*72*20);
  1299.  
  1300. }
  1301.  
  1302. /*************************************************************************
  1303. Returns the current Horizontal cursor location in TWIPS
  1304. *************************************************************************/
  1305. int FAR PASCAL PagePosX(void)
  1306. {
  1307.  
  1308.     return ((PageInfo.ptCurrentPos.x/PrinterInfo.ptResolution.x)*72*20);
  1309.  
  1310. }
  1311.  
  1312. /*************************************************************************
  1313. Returns the vertical page size is TWIPS
  1314. *************************************************************************/
  1315. int FAR PASCAL PageSizeY(void)
  1316. {
  1317.     return ((PrinterInfo.ptPageSize.y/PrinterInfo.ptResolution.y)*72*20);
  1318.  
  1319. }
  1320.  
  1321. /*************************************************************************
  1322. Returns the horizontal page size in TWIPS
  1323. *************************************************************************/
  1324. int FAR PASCAL PageSizeX(void)
  1325. {
  1326.     return ((PrinterInfo.ptPageSize.x/PrinterInfo.ptResolution.x)*72*20);
  1327.  
  1328. }
  1329.  
  1330. /*************************************************************************
  1331.     Exported Draw Line Function, takes it parameters in TWIPS
  1332. *************************************************************************/
  1333. BOOL    FAR PASCAL    DrawLine(int nX1, int nY1, int nX2, int nY2)
  1334. {
  1335.     nX1 = MulDiv(nX1, PrinterInfo.ptResolution.x, (72 * 20));
  1336.     nY1 = MulDiv(nY1, PrinterInfo.ptResolution.y, (72 * 20));
  1337.     nX2 = MulDiv(nX2, PrinterInfo.ptResolution.x, (72 * 20));
  1338.     nY2 = MulDiv(nY2, PrinterInfo.ptResolution.y, (72 * 20));
  1339.  
  1340.     return FDrawLine(ppPrinter.hDC, nX1, nY1, nX2, nY2);
  1341. }
  1342.  
  1343. /*************************************************************************
  1344.     Exported Draw Rectangle Function, takes it parameters in TWIPS
  1345. *************************************************************************/
  1346. BOOL    FAR PASCAL    DrawRectangle(int nX1, int nY1, int nX2, int nY2)
  1347. {
  1348.  
  1349.     nX1 = MulDiv(nX1, PrinterInfo.ptResolution.x, (72 * 20));
  1350.     nY1 = MulDiv(nY1, PrinterInfo.ptResolution.y, (72 * 20));
  1351.     nX2 = MulDiv(nX2, PrinterInfo.ptResolution.x, (72 * 20));
  1352.     nY2 = MulDiv(nY2, PrinterInfo.ptResolution.y, (72 * 20));
  1353.  
  1354.     return FDrawRectangle(ppPrinter.hDC, nX1, nY1, nX2, nY2);
  1355. }
  1356.  
  1357. /*************************************************************************
  1358.     Exported Draw Rounded Rectangle Function, takes it
  1359.     parameters in TWIPS
  1360. *************************************************************************/
  1361. BOOL    FAR    PASCAL    DrawRndRectangle(int nX1, int nY1, int nX2, int nY2, int nX3, int nY3)
  1362. {
  1363.  
  1364.     nX1 = MulDiv(nX1, PrinterInfo.ptResolution.x, (72 * 20));
  1365.     nY1 = MulDiv(nY1, PrinterInfo.ptResolution.y, (72 * 20));
  1366.     nX2 = MulDiv(nX2, PrinterInfo.ptResolution.x, (72 * 20));
  1367.     nY2 = MulDiv(nY2, PrinterInfo.ptResolution.y, (72 * 20));
  1368.     nX3 = MulDiv(nX3, PrinterInfo.ptResolution.x, (72 * 20));
  1369.     nY3 = MulDiv(nY3, PrinterInfo.ptResolution.y, (72 * 20));
  1370.  
  1371.     return FDrawRndRectangle(ppPrinter.hDC, nX1, nY1, nX2, nY2, nX3, nY3);
  1372. }
  1373.  
  1374. /*************************************************************************
  1375.     Exported Draw Ellipse Function, takes it parameters in TWIPS
  1376. *************************************************************************/
  1377. BOOL    FAR PASCAL    DrawEllipse(int nX1, int nY1, int nX2, int nY2)
  1378. {
  1379.     nX1 = MulDiv(nX1, PrinterInfo.ptResolution.x, (72 * 20));
  1380.     nY1 = MulDiv(nY1, PrinterInfo.ptResolution.y, (72 * 20));
  1381.     nX2 = MulDiv(nX2, PrinterInfo.ptResolution.x, (72 * 20));
  1382.     nY2 = MulDiv(nY2, PrinterInfo.ptResolution.y, (72 * 20));
  1383.  
  1384.     return FDrawEllipse(    ppPrinter.hDC, nX1, nY1, nX2, nY2);
  1385.  
  1386. }
  1387.  
  1388.  
  1389.  
  1390. /*************************************************************************
  1391.     Unconditionally moves the current cursor position
  1392.     in the Y direction, takes its parameters in 100th's
  1393.     of an inch.
  1394. *************************************************************************/
  1395. BOOL FAR PASCAL    MoveYPos(int nY)
  1396. {
  1397.     PageInfo.ptCurrentPos.y += (int)((nY * PrinterInfo.ptResolution.y)/100);
  1398.     if(PageInfo.ptCurrentPos.y > (PrinterInfo.ptPageSize.y - PrinterInfo.rcMargins.top - PrinterInfo.rcMargins.bottom))
  1399.     {
  1400.         EjectPage();        // Sets current positon too
  1401.     }
  1402.     return TRUE;
  1403.  
  1404. }
  1405.  
  1406. /*************************************************************************
  1407.     End of VBPRINT.DLL
  1408. *************************************************************************/
  1409.